赛博博饼:一个 Vibe Coding 出来的中秋小游戏
在国庆节放假终于修修改改做出了一个基本完善的博饼小游戏,那就写一篇记录一下吧哈哈哈哈(
直接玩:woo3an.top/bobing
备用地址:woo3an.github.io/bobing
为什么会想做这个游戏呢?其实是中秋前的周末回了趟家,和妈妈去买药,发现博饼活动甚至在药店都开始了,她甚至还博到了状元哈哈哈。简单的公众号就可以参与这种活动,那我想,作为一个厦门本地人,我也想要自己做一个这样的游戏,agent 和大模型也一定可以帮我做出这样的网页游戏吧?
于是就有了这样一个不断迭代的 vibe coding 历程。
需要先给没接触过的朋友介绍一下:
厦门的博饼是什么?怎么玩?
博饼是什么?
博饼是闽南地区(厦门、泉州、漳州一带)中秋特有的民俗活动,相传起源于明末清初,是郑成功屯兵厦门时让士兵中秋解闷的活动。玩法就是大家围着一只大碗轮流掷六颗骰子,根据点数组合拿不同的“饼”——传统上奖品是月饼,现在什么都可能有。
中秋前后,这是厦门人一定会进行的一项传统活动。在这几天里,家家户户都会传出来骰子扔进瓷碗里发出的清脆的声音。
具体的玩法
其实也很简单。六颗骰子扔进碗里,奖项从小到大依次是:
- 一秀:一个四点
- 二举:两个四点
- 四进:四个相同点数(非四点)
- 三红:三个四点
- 对堂:1 到 6 各一颗
- 四点红:四个四点 + 两个其他点数(非两个一点)
- 五子登科:五个相同点数(非四点)
- 五红:五个四点
- 六勃黑:六个相同点数(二、三、五、六,按点数比大小)
- 遍地锦:六个一点
- 六抔红:六个四点
- 状元插金花:四个四点 + 两个一点
从四点红开始,都算“状元”,只是大小不同。状元可以被更大的状元抢走——比如你先博了个四点红,别人后面博了个五红,状元就归他了;如果别人博的比你小,你的状元就保住了。同级的话,先博的人保留。
需要注意的是,即使在厦门地区对状元的大小排序也依然有争议,有人认为六抔红比状元插金花大,状元插金花应该是最小的状元。在这里我们还是按照状元插金花最大的规则。

那么,回到项目本身,这个网页究竟是什么?
最终的成品是一个闽南中秋博饼的网页版。六颗骰子丢进大红碗,有完整的建模,博状元、对堂、三红、四进、二举、一秀。

核心玩法跟真的博饼一样,但加了一些我想要的更丰富的功能:
- 1–15 人同机传阅:一台手机或电脑,几个人轮流点,自动轮流开博。
- 跨设备联机:各自用自己的手机,开房间一起玩,会有一定的延迟,但是对于这个游戏来说不影响。
- 自动模式:挂机它自己博,博到本局结束,非常轻松的玩法。
- 掉线托管:有人掉线了,AI 自动替他博几把,不至于卡住整个局。

我个人最推荐的还是单机多人博饼——一群人围在一台电脑前,一个人点一下,这也更像是真正的一群人围在一起博饼。
这个项目是怎么来的呢?
全是 Vibe Coding。
这个项目完全是我和 AI 聊天聊出来的。从第一次对话到现在的样子,大概经历了这么几个阶段。
9 月 14 日,诞生。 前一天晚上,也就是我回到 XMU 的周天晚上,我在 WorkBuddy 里正式开始了这个项目。最开始只是一个很简单的想法:做一个有建模的博饼小游戏,同时要把博饼规则搞清楚。真实的博饼规则要用到程序里,对人来说还是有点复杂的。光把 6⁶ = 46656 种骰面组合穷举明白,再用精确规则排出大小顺序,就够写一阵了。幸好它是 AI。那天做出来的版本已经比较完整:单文件、零依赖、物理骰子能弹跳能撞碗壁(虽然建模透视有问题)、WebAudio 现场合成的骰子声、本地传阅 2–6 人。同时也上线了 GitHub Pages,舍友可以用网页开博了。
9 月 15 到 16 日,打磨视觉和玩法。 正式定名「中秋博饼」。碗精细建模了好几轮,滚金边、月牙、釉色更深更红,骰子擦亮、修正了“平面压缩两次”的问题,让这个模型看起来更符合现实了。同时,自动模式上线,挂机能博到本局结束了,这是真正解放双手的轮椅功能,甚至可以成为上课无聊的消遣哈哈哈。也是在这两天,几个有争议的玩法口径定下来了——状元以每人最后博出的为准,收官轮从最后得奖者的下家起算。规则清楚了,后面才好继续加东西。

9 月 17 日,联机正式版。 这时的我想到,如果大家不在一个地方也想要一起博饼呢?那就加一个联机模式吧。在我不断的对话中,联机从一开始的实验方案(PeerJS、CloudBase)全面切换到了自建 Cloudflare Worker + Durable Object。这个决定后面看非常正确:WebSocket 常驻推送、零月费、每个房间号一个独立对象。后面的完善功能,比如掉线跳过、断线自动重连、再来一局、身份持久化,都是基于这个方案来的。为此我还购买了域名 woo3an.top,可以说,我真正拥有了自己的网站,后面我也给它部署了另一个博客。

9 月 18 到 20 日,完善托管和观战。 联机最麻烦的不是连上,是有人掉线怎么办。这几天的重点就是自动处置:15 秒没动静就允许别人代博,代博最多 5 把,之后自动跳过;2 分钟内回来一切照常,超了就当彻底断线。后来又补上了观战模式——被移出本局的人重连不再被拒,放进来只看不玩,下一局可以照常参与。
9 月 21 到 27 日,细节修复期。 夜间模式下骰子变黑、弹层标题被滚走、碰撞音效不够像录音……这些问题都是在这段时间一点点磨掉的。碰撞声在这阶段做了一轮大改:按真实录音的频谱逐项拟合,用合成器重建——展宽共振、补低频、延长余韵,听起来比原版好一些,但本质还是合成音,而且越听越让我觉得像金属碰撞声音,不过那几天太忙了我也没有再去修改它。
10 月 2 到 3 日,最终完善与部署自动化。 音效在这时候又往前走了一步:碰撞声从合成音换成了真实录音采样。截了录音里最脆的那记碰撞,再进行一些处理,这次尽量去模拟真的“骰子撞瓷碗”了。最后还补上的是工程化那部分。此前 Worker 只能本机 wrangler deploy,跟博客那边的自动部署不一致。补了 GitHub Actions,现在两个站点都是推到 main 就上线。还做了一件重要的事:把游戏 Worker 和博客 Worker 拆开——之前两个项目用同一个 Worker 名,谁后部署谁把对方覆盖掉,博客差点因此没了。
整个项目就是一个 index.html,零外部依赖,打开就玩。联机后端放在 cf/ 目录,用 wrangler 部署。
一些技术上的碎碎念
虽然说是 Vibe Coding,但其实还是有不少反复纠结的设计决策。
为什么最后选了 Cloudflare Workers + Durable Object? 联机一开始试过 PeerJS 和 CloudBase。PeerJS 的问题是信令服务不稳定,朋友在学校网络下容易连不上,至于腾讯的 CloudBase 免费版连安全域名都配不了,根本没法用。后来换成 Cloudflare,每个房间号对应一个独立的 Durable Object,WebSocket 常驻推送,谁在哪个房间、房间什么状态,都是这个对象在管。免费额度对“几个朋友偶尔玩”来说绰绰有余。
免费额度到底能撑多少? 我让 AI 算过一笔账:主要的瓶颈是 SQLite 行写,每天 10 万行。正常一局大概写 270 行,算上托管最多 285 行。所以理论上每天能跑 300+ 局。对个人项目来说,这个数根本用不完。
掉线托管是联机最麻烦的部分。 我花了很多时间让 AI 做自动处置,在这个过程中出现了好多问题,比如代博直接卡住、重连进不去之类的问题,不过幸好最终都一一解决了。最后我发现,这些东西好像也没有很多的应用场景呀(
还有音效。 这块折腾了最久。最开始是 WebAudio 现场合成,听感像劣质塑料,不过其实还挺上头的哈哈哈。后来按真实录音的频谱逐项拟合,用合成器重建——展宽共振、补低频、延长余韵,好了一点,但本质还是合成音,而且越听越觉得奇怪。直到 10 月,才换成真实录音采样:截了录音里最脆的那记碰撞,再经过 AI 一系列我看不懂的音频处理,这次终于比较像骰子撞瓷碗了。
一点个人感受
做完联机之后,我反而更推荐单机多人。
联机很方便,各自拿手机就能玩,异地也能凑一局。但博饼归根到底,最有意思的还是一群人围在一起。一个人博一下,骰子在碗里来回碰撞,发出清脆的声音,四周的人露出期待的眼神。有人博了个一秀大家一起开玩笑说“对的对的”,有人一出手就是状元也会让全场震惊。这样的气氛,各自捧一台手机是给不了的。

赛博博饼做出来,其实终究只是一个不完美的替代品。如果有条件的话,还是希望大家能够围在一起,放下手机,感受一下真正的博饼穿越百年时光带来的乐趣。
一个迟到的中秋快乐
这个项目 9 月 14 号第一次上线,到今天差不多三周,一直在打磨。写它的时候是中秋前,等发出来已经过了中秋。
目前可能还存在一些 bug,欢迎在仓库里反馈。
特别感谢 DeepSeek-V4.1 Flash、GLM-5.3-Flash、Hy4 preview 以及 WorkBuddy 的支持。是的,就连这篇博客的草稿也是和 AI 一起完成的。
Make Bobing Great Again!